package com.qfedu.lc.user.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.jwt.JWTUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qfedu.lc.common.config.RabbitKeyConfig;
import com.qfedu.lc.common.config.RedisKeyConfig;
import com.qfedu.lc.common.param.GrowthAdd;
import com.qfedu.lc.common.param.MqMsg;
import com.qfedu.lc.common.param.UserAdd;
import com.qfedu.lc.common.param.UserLogin;
import com.qfedu.lc.common.util.JwtUtil;
import com.qfedu.lc.common.vo.R;
import com.qfedu.lc.user.entity.Log;
import com.qfedu.lc.user.entity.User;
import com.qfedu.lc.user.mapper.LogMapper;
import com.qfedu.lc.user.mapper.UserMapper;
import com.qfedu.lc.user.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDate;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import static com.qfedu.lc.common.config.RedisKeyConfig.LOGIN_UID_TOKEN;

/**
 * <p>
 * 1.用户表 服务实现类
 * </p>
 *
 * @author KK
 * @since 2024-06-05
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private LogMapper logMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 1.判断参数是否为空
     * 2.判断验证码是否匹配 redis
     * 3.判断手机号是否重复  账号是否重复
     * 4.密码加密 插入user表
     * 5.记录用户日志
     * 6.删除注册验证码
     *
     * @param userAdd
     * @return
     */
    @Override
    public R register(HttpServletRequest request, UserAdd userAdd) {
        //1.判断参数是否为空
        if (userAdd == null || StringUtils.isAnyEmpty(userAdd.getAccount(), userAdd.getCode(), userAdd.getPassword(), userAdd.getPhone())) {
            return R.fail("参数错误");
        }

        // 2.判断验证码是否匹配 redis
        String redisCode = stringRedisTemplate.opsForValue().get(RedisKeyConfig.SMS_RCODE + userAdd.getPhone());
        if (!userAdd.getCode().equals(redisCode)) {
            return R.fail("验证码错误");
        }

        // 3.判断手机号是否重复
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("phone", userAdd.getPhone());
        List<User> userList = userMapper.selectList(userQueryWrapper);
        if (userList != null && userList.size() > 0) {
            return R.fail("手机号用户已存在");
        }

        // 4.密码加密 插入user表
        User user = new User();
        user.setPhone(userAdd.getPhone())
                .setAccount(userAdd.getAccount())
                .setStatus(1)
                .setPassword(SecureUtil.md5(userAdd.getPassword()))
                .setCtime(new Date());
        int i = userMapper.insert(user);
        if (i <= 0) {
            return R.fail("注册失败");
        }

        //5.记录用户日志
        Log log = new Log();
        log.setId(user.getId());
        log.setUserId(user.getId());
        log.setType("用户注册");
        log.setIp(request.getRemoteHost());
        log.setInfo(user.getPhone() + "用户注册");
        log.setMobile(user.getPhone());
        log.setCtime(new Date());

        logMapper.insert(log);

        //6.删除redis中的验证码
        stringRedisTemplate.delete(RedisKeyConfig.SMS_RCODE + userAdd.getPhone());

        // 7.积分增加 发送消息
        MqMsg mqMsg = new MqMsg();
        mqMsg.setId(IdUtil.getSnowflakeNextId());
        mqMsg.setType(5);

        GrowthAdd growthAdd = new GrowthAdd();
        growthAdd.setUid(user.getId());
        growthAdd.setType("新用户注册");
        growthAdd.setGrowth(50);

        mqMsg.setMsg(growthAdd);

        rabbitTemplate.convertAndSend("", RabbitKeyConfig.Q_USER_GROWTH,mqMsg);
        return R.ok("注册成功");


    }

    /**
     * 使用 账号 + 密码登录
     * 1.判断参数是否为空
     * 2.判断账户是存在，可用
     * 3.判断登录次数是否超过三次
     * 4.验证用户 密码
     * 5.生成token
     * 6.存储token
     * 7.记录登录日志
     * 8.返回token
     *
     * @param userLogin
     * @return
     */
    @Override
    public R loginPass(UserLogin userLogin) {

        //1.判断参数是否为空
        if (userLogin == null || StringUtils.isAnyEmpty(userLogin.getPass(), userLogin.getName())) {
            return R.fail("参数错误");
        }

        //2.判断账户是存在，可用
        String account = userLogin.getName();
        String password = userLogin.getPass();
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("account", account);
        List<User> userList = userMapper.selectList(userQueryWrapper);
        if (userList == null || userList.size() == 0) {
            return R.fail("该用户不存在");
        }

        //3.判断登录次数是否超过三次
        User user = userList.get(0);
        Set<String> keys = stringRedisTemplate.keys(LOGIN_UID_TOKEN + user.getId() + "*");
        if (keys != null && keys.size() > 3) {
            return R.fail("登录超过三次");
        }
        //4.验证用户 密码

        if (!user.getPassword().equals(SecureUtil.md5(password))) {
            return R.fail("账号或者密码错误");
        }
        //5.生成token
        String jwt = JwtUtil.createJwt(user.getId(), account, user.getPhone());

        //6.存储token
        stringRedisTemplate.opsForValue().set(LOGIN_UID_TOKEN + user.getId() + ":" + jwt, "", 12 * 60 * 60, TimeUnit.SECONDS);
        redisTemplate.opsForValue().set(RedisKeyConfig.LOGIN_TOKEN + jwt, user, 12 * 60 * 60, TimeUnit.SECONDS);
        //7.记录登录日志

        Log log = new Log();
        log.setUserId(user.getId())
                .setMobile(user.getPhone())
                .setInfo(user.getPhone() + "用户登录")
                .setType("用户登录")
                .setCtime(new Date());

        logMapper.insert(log);

        // 7.每天首次登录积分增加2，同一天再次登录，积分不增加
        String userLoginDateKey = "LOGIN_DATE_" + user.getId() + "_" + LocalDate.now().toString();
        if (!stringRedisTemplate.hasKey(userLoginDateKey)) {
            // 当天首次登录加 2 分
            GrowthAdd growthAddFirstLogin = new GrowthAdd();
            growthAddFirstLogin.setUid(user.getId());
            growthAddFirstLogin.setType("每日首次登录");
            growthAddFirstLogin.setGrowth(2);
            MqMsg mqMsgFirstLogin = new MqMsg();
            mqMsgFirstLogin.setId(IdUtil.getSnowflakeNextId());
            mqMsgFirstLogin.setType(5);
            mqMsgFirstLogin.setMsg(growthAddFirstLogin);
            rabbitTemplate.convertAndSend("", RabbitKeyConfig.Q_USER_GROWTH, mqMsgFirstLogin);
            // Store key for today's login
            stringRedisTemplate.opsForValue().set(userLoginDateKey, "logged", 1, TimeUnit.DAYS);
        }


        //8.返回token
        return R.ok(jwt);
    }

    @Override
    public R logincode(HttpServletRequest request, UserLogin userLogin) {
        //1.判断参数是否为空
        if (userLogin == null || StringUtils.isAnyEmpty(userLogin.getName(), userLogin.getPass())) {
            return R.fail("参数错误");
        }
        //2.校验验证码
        String redisCode = stringRedisTemplate.opsForValue().get(RedisKeyConfig.SMS_RCODE + userLogin.getPhone());
        if (!userLogin.getPass().equals(redisCode)) {
            return R.fail("验证码错误");
        }
        //5.记录用户日志
        Log log = new Log();
        User user = new User();
        log.setUserId(user.getId())
                .setMobile(user.getPhone())
                .setInfo(user.getPhone() + "用户登录")
                .setType("用户登录")
                .setIp(request.getRemoteHost())
                .setCtime(new Date());

        logMapper.insert(log);


        //删除redis中的验证码
        stringRedisTemplate.delete(RedisKeyConfig.SMS_RCODE + userLogin.getPhone());
        return R.ok("登录成功");
    }


    /**
     * 1.从header中获取token
     * 2.更新token 获取用户信息
     * 3.删除改用相关的token、
     * 4. 响应前端
     *
     * @param token
     * @return
     */
    @Override
    public R logout(String token) {
        //2.更新token 获取用户信息
        User user = (User) redisTemplate.opsForValue().get(RedisKeyConfig.LOGIN_TOKEN + token);
        //3.删除改用相关的token
        redisTemplate.delete(RedisKeyConfig.LOGIN_TOKEN + token);
        stringRedisTemplate.delete(LOGIN_UID_TOKEN + user.getId()+":"+token);
        return R.ok("退出成功");

    }
}
